package org.traffometer.traffobase.model;

import java.util.ArrayList;
import java.util.Iterator;

import edu.hawaii.stack.ClearStack;
import edu.hawaii.stack.EmptyStackException;

/**
 * Implements a singleton ClearStack instance.
 * The command classes manipulate this singleton in response to user input.
 * The StackModel manipulates string objects only.
 * To prevent multi-threaded access from corrupting the stack, all operations on the
 * singleton StackModel instance are synchronized.
 *
 * @author Jitender Miglani
 * @author Philip Johnson
 */
public class StackModel {

  /** The singleton StackModel instance. */
  private static StackModel theInstance = new StackModel();

  /** The internal stack implementation. */
  private ClearStack stack;

  /** Private constructor used to create a single instance of stack. */
  private StackModel() {
    this.stack = new ClearStack();
  }

  /**
   * Get the single instance of StackModel object.
   *
   * @return A StackModel.
   */
  public static synchronized StackModel getInstance() {
    return StackModel.theInstance;
  }

  /**
   * Pushes a string object onto the stack.
   *
   * @param value The string to be pushed.
   */
  public synchronized void push(String value) {
    this.stack.push(value);
  }

  /**
   * Pops a string value out of the stack.
   *
   * @return The value popped out of the stack.
   * @throws EmptyStackException If an empty stack was popped.
   */
  public synchronized String pop() throws EmptyStackException {
    return (String) this.stack.pop();
  }

  /** Clears the stack. */
  public synchronized void clearStack() {
    this.stack = new ClearStack();
  }

  /**
   * Gets the iterator attribute of the StackModel object.
   *
   * @return The iterator value.
   */
  public synchronized Iterator iterator() {
    return this.stack.getIterator();
  }

  /**
   * Gets the top attribute of the StackModel object.
   *
   * @return The top value.
   * @exception EmptyStackException If the stack is empty.
   */
  public synchronized Object getTop() throws EmptyStackException {
    return this.stack.getTop();
  }

  /**
   * Doubles the contents of the stack.
   * For example, if the stack contains 1 2 3, the result after this method will be 1 2 3 1 2 3.
   */
  public synchronized void doubleIt() {
    Iterator stackIterator = this.stack.getIterator();
    ArrayList<String> tempArray = new ArrayList<String>();

    //Iterate through the stack and get the elements.
    while (stackIterator.hasNext()) {
      String element = (String) stackIterator.next();
      tempArray.add(element);
    }

    //Push the elements in tempArray onto the stack.
    for (String newElement : tempArray) {
      this.stack.push(newElement);
    }
  }
}
